﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "GcmpGeometryInterface.h"
#include "IGeometry.h"
#include "OwnerPtr.h"
#include "Box2d.h"
#include "ICoedgeMap.h"

namespace gcmp
{
    class IPolyCurve;

    /// \brief 多边形（二维）
    ///
    /// 由多个封闭的多段线组成，多段线间间无相交，允许存在多个外环，最外面的环必须是外环，外环与内环允许交替出现
    class IPolygon : public IGeometry
    {
        DEFINE_CAST_DERIVED(gcmp::IPolygon, gcmp::IGeometry);
    public:
        /// \brief  创建一个空的多边形
        /// \return  多边形(不包含任何线)
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolygon> Create();

    public:
        

        /// \brief   获取二维包围盒
        /// \return  二维包围盒
        virtual Box2d GetBox2d() const = 0;

        /// \brief   获取多边形中多段线的数量
        /// \return  多段线的数量
        virtual int GetPolyCurveCount() const = 0;

        /// \brief  向多边形中添加多段线(拷贝实现)
        /// \param pIPolyCurve    多段线
        /// \return 返回多段线在多边形中的索引
        virtual int AddPolyCurveByClone(const IPolyCurve* pIPolyCurve) = 0;

        /// \brief  在多边形指定位置插入一个多段线
        /// \param index    索引
        /// \param pIPolyCurve    多段线
        /// \return  成功返回True，失败返回False
        virtual bool InsertPolyCurveByClone(int index, const IPolyCurve* pIPolyCurve) = 0;

        /// \brief  获取指定索引位置的多段线(拷贝实现)
        /// \param index    索引
        /// \return 索引在二维边链表范围内返回拷贝后的多段线，否则返回空
        virtual OwnerPtr<IPolyCurve> GetPolyCurve(int index)const = 0;

        /// \brief  计算多边形的重心
        /// \param centroidPoint    多边形的重心
        /// \return 重心计算成功返回True，失败返回False
        virtual bool GetCentroid(Vector2d& centroidPoint)const = 0;

        /// \brief  检测多边形是否合法（合法性检查包含：外环逆时针内环顺时针、逆时针环和顺时针环交替出现、多段线封闭、多段线无自交）
        /// \return 合法返回True，不合法返回False
        virtual bool IsRegularized()const = 0;

        /// \brief  设置多边形的距离容差
        /// \param distanceEpsilon 距离容差
        /// \return  成功返回True，失败返回False
        virtual bool SetDistEpsilon(double distanceEpsilon) = 0;

        /// \brief  返回多边形的距离容差
        ///
        /// 如对该多边形进行过合并等操作（比如MergeCurves）或者调用 CalculateDistEpsilon，具体返回值见 CalculateDistEpsilon
        /// \return  距离容差
        virtual double GetDistEpsilon() = 0;

        /// \brief  返回多边形中实际环容差的最大值，如果此最大值小于1e-4，那么返回1e-4
        ///
        /// 注意这里不会去改变多边形的距离容差
        /// \return 多边形中实际环容差的最大值，如果此最大值小于1e-4，那么返回1e-4
        virtual double GetMaxDistEpsilon() = 0;

        /// \brief  计算多边形容差
        /// 具体计算方法：1、计算多边形中所有环的容差，取最大值得 A；2、比较 A 与1e-4, 取大者得 B；3、如果 B 比多边形当前容差大，那么将多边形容差设置为 B；
        virtual void CalculateDistEpsilon() = 0;

        /// \brief  合并可以合并的边，简化表示
        /// \param distanceEpsilon    曲线间允许的最小间距
        /// \param angleEpsilon   曲线间允许的最小间距
        /// \return   如果有合并，返回true, 否则返回false
        virtual bool MergeCurves(double distanceEpsilon, double angleEpsilon) = 0;

        /// \brief 删除指定索引的环
        /// \param[in] int nIndex   环索引
        virtual void DeletePolyCurve(int index) = 0;

        /// \brief 判断多边形是否只包含直线段
        /// \return 只包含直线段返回true,否则返回false
        virtual bool IsOnlyLines() const = 0;

        /// \brief 判断多边形是否只包含直线段或圆弧
        /// \return 只包含直线段或圆弧返回true,否则返回false
        virtual bool IsOnlyLinesOrArcs() const = 0;

        /// \brief  将多边形分解，生成连通的多边形集合;
        /// \param [in,out] connectedPolygons 连通的多边形集合
        /// \return void
        virtual void CreateConnectedPolygons(std::vector<OwnerPtr<IPolygon>> &connectedPolygons) = 0;

        /// \brief  对Polygon做镜像
        ///
        /// \param mirrorMatrix          镜像矩阵
        /// \param opOffsetPolygon       镜像后的Polygon
        /// \return 镜像前后，边的对应关系
        virtual OwnerPtr<IMirrorCoedgeMap> Mirror(const Matrix4d& mirrorMatrix, OwnerPtr<IPolygon>& opPolygon) const = 0;

        /// \brief     修复多边形，多线程安全等级：多线程安全
        /// \param[in] dDistEpsilon  距离容差，建议取max(yourDistEpsilon, poly->distEpsilon + g_distEpsilon)，
        /// \其中yourDistEpsilon根据实际情况传入，一般传入0.1或根据图元精度来设置；
        /// \对于存在缝隙的多边形，传入的distEpsilon需大于缝隙的长度才能补缝，如果容差过小，
        /// \会导致成环失败，缝隙未能补上，若缝隙与极短边同时存在，删除极短边会导致缝隙扩大，
        /// \如果容差不合适导致求交结果不准确从而导致成环失败或修复结果不理想
        /// \param[in] mergeCoedges 是否需要mergeCoedges操作，默认false
        /// \param[in] dAngleEpsilon mergeCoedges过程中的角度容差，默认系统角度容差
        /// \return    处理后的多边形，外部负责释放，修复失败会返回null
        virtual OwnerPtr<IPolygon> PolygonRepair(double dDistEpsilon, double dAngleEpsilon = 1e-3, bool mergeCoedges = false) const = 0;

        /// \brief 把多边形反向，即把内部的所有环反向
        virtual void Reverse() const = 0;

    public:
        virtual ~IPolygon() {}
    };
}
